package tt.dz.dao.base;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.sql.SQLException;
import java.util.List;

import javax.annotation.Resource;
import javax.persistence.Table;

import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import tt.dz.common.PageModel;

/**
 * 基础Dao类，
 * @author Xielf
 * @param <T>
 */
@Repository
@SuppressWarnings(value = "all")
public class BaseDao<T> extends HibernateDaoSupport {

	/**
	 * 注入Hibernate sessionFactory
	 * @param sessionFactory Hibernate session工场（spring自动注入）
	 */
	@Resource
	public void setSessionFacotry(SessionFactory sessionFacotry) {
		super.setSessionFactory(sessionFacotry);
	}

	/**
	 * 保存对象
	 * @param obj 保存对象
	 * @return	反馈序列
	 */
	public Serializable save(final Object obj) {
		Serializable s = this.getHibernateTemplate().save(obj);
		return s;
	}

	/**
	 * 修改对象
	 * @param obj
	 */
	public void update(final Object obj) {
		this.getHibernateTemplate().update(obj);
	}

	/**
	 * 物理删除
	 * @param obj
	 */
	public void physicallyDelete(final Object obj) {
		this.getHibernateTemplate().delete(obj);
	}

	/**
	 * 逻辑删除（目前不可用）
	 * @param cls	类
	 * @param Idname
	 * @param IdValue
	 */
	public void logicDelete(final Class<T> cls, String Idname, String IdValue) {
		Annotation annotations[] = cls.getAnnotations();
		for (Annotation annotation : annotations) {
			final Class<? extends Annotation> ancls = annotation
					.annotationType();
			if (ancls.equals(Table.class)) {
				try {
					Table tableAnnotation = cls.getAnnotation(Table.class);
					String tableName = tableAnnotation.name();
					this.executeBySql("UPDATE " + tableName
							+ " SET validflag=0 WHERE " + Idname + "=?",
							IdValue);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 查询
	 * @param hql
	 * @param params可变参数
	 * @return
	 */
	public List<T> findByHql(final String hql, final Object... params) {
		return this.getHibernateTemplate().execute(
				new HibernateCallback<List<T>>() {
					public List<T> doInHibernate(Session session)
							throws HibernateException, SQLException {
						//得到查询对象
						Query query = session.createQuery(hql);
						//设置参数
						if (params != null && params.length > 0) {
							for (int i = 0; i < params.length; i++) {
								query.setParameter(i, params[i]);
							}
						}
						//缓存查询
						return query.setCacheable(true).list();
					}
				});
	}

	/**
	 * 通过hql查询分页
	 * 
	 * @param hql
	 * @param pageNo 页码
	 * @param pageSize	每页显示条数
	 * @param params	可变参数
	 * @return
	 */
	public List<T> findPagingByHql(final String hql, final Integer pageNo,
			final Integer pageSize, final Object... params) {
		
		return this.getHibernateTemplate().execute(
				new HibernateCallback<List<T>>() {
					public List<T> doInHibernate(Session session)
							throws HibernateException, SQLException {
						//得到查询对象
						Query query = session.createQuery(hql);
						//设置起始查询条数
						query.setFirstResult((pageNo - 1) * pageSize);
						//设置查询条数
						query.setMaxResults(pageSize);
						//设置参数
						if (params != null && params.length > 0) {
							for (int i = 0; i < params.length; i++) {
								query.setParameter(i, params[i]);
							}
						}
						return query.setCacheable(true).list();
					}
				});
	}

	/**
	 * sql查詢
	 * 
	 * @param sql sql语句
	 * @param cls	封装类（可空（缓存机制不可用））
	 * @param params	可变参数
	 * @return
	 */
	public List<Object> findBySql(final String sql, final Class<?> cls,
			final Object... params) {
		
		return this.getHibernateTemplate().execute(
				new HibernateCallback<List<Object>>() {
					public List<Object> doInHibernate(Session session)
							throws HibernateException, SQLException {
						SQLQuery query = session.createSQLQuery(sql);

						if (params != null && params.length > 0) {
							for (int i = 0; i < params.length; i++) {
								query.setParameter(i, params[i]);
							}
						}
						if (cls != null) {
							//查询并封装类
							return query.addEntity(cls).setCacheable(true)
									.list();
						} else {
							return query.list();
						}
					}
				});
	}

	/**
	 * 通过Sql查询分页
	 * 
	 * @param sql sql语句
	 * @param pageNo	页码
	 * @param pageSize	显示条数
	 * @param params 可变参数
	 * @return
	 */
	public List<T> findPagingBySql(final String sql, final Class<Object> cls,
			final Integer pageNo, final Integer pageSize,
			final Object... params) {
		return this.getHibernateTemplate().execute(
				new HibernateCallback<List<T>>() {
					public List<T> doInHibernate(Session session)
							throws HibernateException, SQLException {
						SQLQuery query = session.createSQLQuery(sql);
						query.setFirstResult((pageNo - 1) * pageSize);
						query.setMaxResults(pageSize);
						if (params != null && params.length > 0) {
							for (int i = 0; i < params.length; i++) {
								query.setParameter(i, params[i]);
							}
						}
						if (cls != null) {
							return query.addEntity(cls).setCacheable(true)
									.list();
						} else {
							return query.list();
						}
					}
				});

	}

	/**
	 * sql执行修改
	 * @param sql sql语句
	 * @param params	显示条数
	 * @return
	 */
	public Boolean executeBySql(final String sql, final Object... params) {
		return this.getHibernateTemplate().execute(
				new HibernateCallback<Boolean>() {
					public Boolean doInHibernate(Session session)
							throws HibernateException, SQLException {
						SQLQuery query = session.createSQLQuery(sql);

						if (params != null && params.length > 0) {
							for (int i = 0; i < params.length; i++) {
								query.setParameter(i, params[i]);
							}
						}
						return query.executeUpdate() > 0 ? true : false;
					}
				});
	}

	/**
	 * 执行批量插入执行数据的方法
	 * @param objs 对象集合
	 */
	public void batchInsert(List<Object> objs) {
		
		for (int i = 0; i < objs.size(); i++) {
			getHibernateTemplate().save(objs.get(i));
			if (i % 1000 == 0) { 
				// 每一千条刷新并清理一级缓存
				getHibernateTemplate().flush();
				getHibernateTemplate().clear();
			}
		}
	}

	/**
	 * 
	 * 通用的分页查询(默认使用缓存查询)
	 * 
	 * @param Hql	hql语句
	 * @param param
	 *            Hql中的参数
	 * @return PageModel 对象
	 */
	public PageModel<T> findPage(String Hql, PageModel<T> pm, Object... params) {

		//得到SESSIOn
		Session session = super.getSession();
		try {
			String temp = Hql;
			String primarykey = "";
			if (Hql.indexOf("select") != -1) {
				primarykey = temp.substring(Hql.indexOf("select ") + 7,
						Hql.indexOf(","));
				temp = Hql.substring(temp.indexOf("from"));
			}
			//不包含orderby，关键字
			if (Hql.indexOf(" order by") != -1) {
				temp = temp.substring(0, temp.indexOf(" order by"));
			}
			Query query = session.createQuery(new StringBuffer("select count(")
					.append(primarykey == "" ? "*" : primarykey).append(") ")
					.append(temp).toString());
			// 设置参数
			if (params != null && params.length != 0) {
				for (int i = 0; i < params.length; i++) {
					query.setParameter(i, params[i], Hibernate.STRING);
				}
			}
			List lst = query.setCacheable(true).list();
			pm.setTotalRecords(lst.size() > 0 ? Integer.parseInt(lst.get(0)
					.toString()) : 0);
			pm.setTotalPages((pm.getTotalRecords() + pm.getPageSize() - 1)
					/ pm.getPageSize() <= 0 ? 1 : (pm.getTotalRecords()
					+ pm.getPageSize() - 1)
					/ pm.getPageSize());
			pm.setPageNo(pm.getPageNo() > pm.getTotalPages() ? pm.getTotalPages()
					: pm.getPageNo());
			pm.setIndexPageNo(1);
			pm.setLastPageNo(pm.getTotalPages());
			
			//
			query = session.createQuery(Hql);
			// 设置参数
			if (params != null && params.length != 0) {
				for (int i = 0; i < params.length; i++) {
					query.setParameter(i, params[i], Hibernate.STRING);
				}
			}
			query.setMaxResults(pm.getPageSize());
			query.setFirstResult((pm.getPageNo() - 1) * pm.getPageSize());
			pm.setData(query.setCacheable(true).list());
			return pm;
			
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}finally{
			//关闭Session（必须，否则很容易内存溢出）
			session.close();
		}
		
	}

}
